package cui

import (
	"bytes"
	"time"

	"gitee.com/xuender/oils/ids"
	"gitee.com/xuender/pp/pb"
	"github.com/gdamore/tcell/v2"
	"github.com/rivo/tview"
)

// Service 命令行服务.
type Service struct {
	app   *tview.Application
	list  *tview.List
	pages *tview.Pages
	send  func(*pb.Msg)
	me    *pb.User
	users map[ids.ID]*UserData
	// 热键
	keys    map[byte]ids.ID
	bakKeys []byte
	closer  func()
}

// NewService 新建命令行服务.
func NewService() *Service {
	s := &Service{
		app:     tview.NewApplication(),
		list:    tview.NewList(),
		pages:   tview.NewPages(),
		users:   make(map[ids.ID]*UserData),
		keys:    make(map[byte]ids.ID),
		bakKeys: []byte("RASDFGHJKLQWERTYUOPN"),
	}
	s.app.SetInputCapture(s.key)

	return s
}

// UserSize 用户数量.
func (s *Service) UserSize() int {
	return len(s.users)
}

// GetUserData 获取用户信息.
func (s *Service) GetUserData(id ids.ID) *UserData {
	return s.users[id]
}

func (s *Service) key(event *tcell.EventKey) *tcell.EventKey {
	if id, has := s.keys[event.Name()[len(event.Name())-1]]; has {
		s.list.SetCurrentItem(s.users[id].index)
		s.SelectUser(id)
	}

	return event
}

// SetMe 设置我的信息.
func (s *Service) SetMe(me *pb.User) {
	s.me = me
}

// Close 退出.
func (s *Service) Close() {
	s.app.Stop()
}

// RemoveUser 删除用户.
func (s *Service) RemoveUser(id ids.ID) {
	ud, has := s.users[id]
	if !has {
		return
	}

	i := ud.index

	s.pages.RemovePage(id.String())
	s.list.RemoveItem(i)

	for id, u := range s.users {
		if u.index > i {
			s.users[id].index = u.index - 1
		}
	}
	// 去除热键
	for key, v := range s.keys {
		if id == v {
			s.bakKeys = append(s.bakKeys, key)
			delete(s.keys, key)

			break
		}
	}

	delete(s.users, id)
}

// ChangeNick 修改昵称.
func (s *Service) ChangeNick(user *pb.User) {
	id := ids.Bytes(user.ID)
	ud := s.users[id]

	s.list.SetItemText(ud.index, user.Nick, ud.secondary())
}

// AddUser 新增用户.
func (s *Service) AddUser(user *pb.User) {
	id := ids.Bytes(user.ID)
	key := uint8(0)

	if len(s.bakKeys) > 0 {
		key = s.bakKeys[0]
		s.bakKeys = s.bakKeys[1:]
		s.keys[key] = id
	}

	ud := NewUserData(user, s.app, key, s)
	s.users[id] = ud

	if !s.pages.HasFocus() {
		s.SelectUser(id)
	}
}

// SelectUser 选择用户.
func (s *Service) SelectUser(id ids.ID) {
	s.pages.SwitchToPage(id.String())

	if ud, has := s.users[id]; has {
		s.app.SetFocus(ud.input)
		ud.Msgs = 0

		m, _ := s.list.GetItemText(ud.index)
		s.list.SetItemText(ud.index, m, ud.secondary())
	}
}

// Append 增加消息.
func (s *Service) Append(msg *pb.Msg) {
	var id ids.ID
	// 这里要根据msg决定显示式样
	// log.Println(s.me, msg.From)
	isMe := bytes.Equal(s.me.ID, msg.From)
	if isMe {
		id = ids.Bytes(msg.To)
	} else {
		id = ids.Bytes(msg.From)
	}

	if ud, has := s.users[id]; has {
		d := ud.display
		// 未读消息
		if s.list.GetCurrentItem() != ud.index && msg.Type == pb.MsgType_Text {
			ud.Msgs++
			m, _ := s.list.GetItemText(ud.index)
			s.list.SetItemText(ud.index, m, ud.secondary())
		}

		_, _ = d.Write([]byte("[grey]"))
		_, _ = d.Write([]byte(time.Now().Format("15:04:05 ")))

		if isMe {
			_, _ = d.Write([]byte("[white]"))
			_, _ = d.Write([]byte(s.me.Nick))
			_, _ = d.Write([]byte("[grey]: [green]"))
		} else {
			switch msg.Type {
			case pb.MsgType_Debug:
				_, _ = d.Write([]byte("[grey]"))
				_, _ = d.Write([]byte(msg.FromNick))
				_, _ = d.Write([]byte(": "))
			default:
				_, _ = d.Write([]byte("[green]"))
				_, _ = d.Write([]byte(msg.FromNick))
				_, _ = d.Write([]byte("[grey]: [white]"))
			}
		}

		_, _ = d.Write(msg.Data)
		_, _ = d.Write([]byte("\n"))
	}
}

// Sender 消息发送器.
func (s *Service) Sender(send func(*pb.Msg)) {
	s.send = send
}

// Run 运行.
func (s *Service) Run() error {
	listFrame := tview.NewFrame(s.list).
		SetBorders(1, 1, 1, 1, 2, 0).
		AddText("用户列表", true, tview.AlignLeft, tcell.ColorGold)
	displayFrame := tview.NewFrame(s.pages).
		SetBorders(1, 1, 1, 1, 2, 2).
		AddText("沟通记录", true, tview.AlignLeft, tcell.ColorGold)
	listWidth := 25
	mainGrid := tview.NewGrid().
		SetRows(0).
		SetColumns(listWidth, 0)

	mainGrid.SetBorder(false)
	mainGrid.AddItem(listFrame, 0, 0, 1, 1, 0, 0, false)
	mainGrid.AddItem(displayFrame, 0, 1, 1, 1, 0, 0, true)

	go s.refresh()

	err := s.app.SetRoot(mainGrid, true).
		EnableMouse(true).
		Run()

	if s.closer != nil {
		s.closer()
	}
	// nolint: wrapcheck
	return err
}

func (s *Service) refresh() {
	f := 500
	tick := time.NewTicker(time.Duration(f) * time.Millisecond)

	for {
		<-tick.C
		s.app.Draw()
	}
}

// Exit 退出.
func (s *Service) Exit(string) string {
	if s.closer != nil {
		s.closer()
	}

	go s.app.Stop()

	return "按任意键退出"
}

// Closer 关闭通知.
func (s *Service) Closer(closer func()) {
	s.closer = closer
}
